﻿/*******************************************************************
Copyright (c) 2011 이재범

*  Permission is hereby granted, free of charge, to any person
*  obtaining a copy of this software and associated documentation
*  files (the "Software"), to deal in the Software without
*  restriction, including without limitation the rights to use,
*  copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the
*  Software is furnished to do so, subject to the following
*  conditions:
* 
*  The above copyright notice and this permission notice shall be
*  included in all copies or substantial portions of the Software.
* 
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
*  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
*  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
*  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*  OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************/

#include "hash.h"
#include "common.h"
#include <sstream>


void Hash::generate_hash_data()
{
	if(is_normalized == false)
		return;

	hash_data = process_hash_value(equation);
}

string process_hash_value(string original_equation)
{
	string HASH_DATA; // 전체 해시 데이타들을 가지게 된다. 
	string equation = original_equation;

	// 처리할 수식들의 중괄호를 선택한다.
	int max_count = 0; // 가장 깊숙히 들어가 있는 중괄호를 찾기 위해 사용되는 변수
	int count = 0;	
	int find = 0;
	int max_loc; // 가장 깊숙히 들어가 있는 중괄호의 위치

	double det_hash; // 각 Hash 의 Determinant 값

	try
	{
		while (true)
		{
			max_count = 0;
			find = 0;
			count = 0;
			max_loc = 0;

			// 가장 먼저 실행되야 할 부분 (가장 깊숙히 들어간 중괄호) 를 찾는다.
			// 이미 중괄호로 열심히 묶어 주었기 때문에 중괄호만 찾아내면 된다. 
			while (find < static_cast<int>(equation.length()))
			{
				if(equation[find] == '{' || equation[find] == '(')
					count ++;
				else if(equation[find] == '}' || equation[find] == ')')
					count --;

				// 이미 처리한 중괄호 앞에는 \ 를 붙이기로 함
				if(count > max_count)
				{
					if(equation[find] == '{' || equation[find] == '(' || equation[find] == '}' || equation[find] == ')')
					{
						if(find == 0 || equation[find - 1] != '\\')
						{
							max_count = count;
							max_loc = find;
						}
					}
				}

				find ++;
			}

			// 식 전체가 중괄호로 감싸져 있기 때문에 max_count 는 적어도
			// 1 이상이여야만 한다. max_count 가 0 이라는 것은 식의 중괄호
			// 처리를 완료하였다는 의미이다.
			if(max_count == 0)
				break;

			int parenth_process = max_loc; // 우리가 처리하는 중괄호의 위치
			int parenth_process_end = find_match_parenth(parenth_process, equation); // 우리가 처리하는 닫는 중괄호 위치
			equation.insert(parenth_process_end, "\\");
			equation.insert(parenth_process, "\\");

			parenth_process++;
			parenth_process_end = parenth_process_end + 2;

			string equation_process; // 우리가 처리하는 수식 부분, 수식을 감싸는 중괄호는 포함되지 않는다. 
			equation_process = equation.substr(parenth_process + 1, parenth_process_end - parenth_process - 2);
			remove_escape_character(equation_process);

			// 그냥 이 equation_process 에서 optr 로 분리한 뒤, 각각에 대한
			// HASH 값들을 생성하면 된다.

			vector<string> hash_list;
			vector<string> operator_list;

			int process_eq_find = 0;
			string operator_name;
			count = 0;

			// 예를 들어서 {a} 를 처리하면 a 만 equation_process 가 되므로
			// 아래에서 오류가 생긴다. 

			if(equation_process.length() == 0)
			{
				//throw Error::syntax_error(0);
				return "";
			}
			if(equation_process[0] != '{' && equation_process[0] != '(')
			{
				if(equation_process[0] == '\\')
				{
					// \\ 로 시작하는 피연산자 (\alpha) 만 있을 수 도 있다. 
					if(!Equation::is_operator(equation_process, 0, operator_name))
					{
						equation_process.insert(equation_process.begin(), '{');
						equation_process.insert(equation_process.end(), '}');
					}
				}
				else
				{
					equation_process.insert(equation_process.begin(), '{');
					equation_process.insert(equation_process.end(), '}');
				}
			}
			while (process_eq_find < static_cast<int>(equation_process.length()))
			{
				if(equation_process[process_eq_find] == '{' || equation_process[process_eq_find] == '(')
					count ++;
				else if(equation_process[process_eq_find] == '}' || equation_process[process_eq_find] == ')')
					count --;

				if(equation_process[process_eq_find] == '\\' && count == 0)
				{
					if(Equation::is_operator(equation_process, process_eq_find, operator_name))
					{
						operator_list.push_back(operator_name);
						process_eq_find += operator_name.length();
					}				
				}
				else if(equation_process[process_eq_find] == '{' || equation[process_eq_find] == '(')
				{
					if(count == 1)
					{
						int end_parenth = find_match_parenth(process_eq_find, equation_process);

						// hash 함수를 처리할 equation 의 일부분
						string process_equation_hash_part = equation_process.substr(process_eq_find + 1, end_parenth - process_eq_find - 1);

						// get_operand_address_table 함수에서 피연산자 주소 테이블에 따라서
						// equation 에 각 피연산자의 주소로 채워넣는 작업까지 완료한다. 
						string ranked_equation = get_operand_address_table(process_equation_hash_part, det_hash);

						// 이렇게 rank 가 정렬된 수식을 가지고 hash 값을 생성한다.
						string hash_data = generate_hash_code(ranked_equation);
						hash_data.append(" " + double_to_string(det_hash));

						hash_list.push_back(hash_data);
						process_eq_find = end_parenth - 1;
					}
				}

				process_eq_find++;
			}

			string temp_hash_data;

			// 만일 연산자가 이항 연산자 라면
			if(!operator_list.empty() && Equation::is_two_parameter_operator(operator_list[0]))
			{
				// 어차피 교환 불가능한 연산자들은 1 개 밖에 없을 것이므로
				// sort 를 해도 변하는 것이 없다.
				sort(operator_list.begin(), operator_list.end());
				reverse(operator_list.begin(), operator_list.end());

				if(Equation::is_changeable(operator_list[0]))
				{
					sort(hash_list.begin(), hash_list.end());
					reverse(hash_list.begin(), hash_list.end());
				}

				vector<string>::iterator operator_list_pointer = operator_list.begin();
				vector<string>::iterator hash_list_pointer = hash_list.begin();

				temp_hash_data.append(*hash_list_pointer);
				hash_list_pointer ++;

				while (hash_list_pointer != hash_list.end() && operator_list_pointer != operator_list.end())
				{
					temp_hash_data.append(" \\" + *operator_list_pointer);
					temp_hash_data.append(" " + *hash_list_pointer);

					operator_list_pointer++;
					hash_list_pointer ++;
				}
			}
			// 만일 연산자가 단항 연산자 라면
			else if(!operator_list.empty() && !Equation::is_two_parameter_operator(operator_list[0]))
			{
				temp_hash_data.append("\\" + operator_list[0]);
				temp_hash_data.append(" " + hash_list[0]);
			}
			// 연산자가 없다면
			else
			{
				temp_hash_data.append(hash_list[0]);
			}

			HASH_DATA.append(temp_hash_data + "/ ");
		} 
		// 이제 마지막으로 수식 전체가 들어간 것을 추가해 주면 된다.

		string ranked_equation = get_operand_address_table(original_equation, det_hash);
		string hash_data = generate_hash_code(ranked_equation);

		HASH_DATA.append(hash_data); 
		HASH_DATA.append(" " + double_to_string(det_hash));
	}
	catch(Error::syntax_error err)
	{
		cout << err.error_message << endl;
		throw Error::general_error(0);
	}
	return HASH_DATA;
}
string generate_hash_code(string equation)
{
	// equation 전체가 {} 로 감싸져 있는가??

	remove_space(equation);
	// 일단 가장 깊숙히 들어가 있는 교환 가능한 이항 연산자를 찾아야 한다.
	// 그리고 그 교환 가능한 이항 연산자의 부분 부터 차례대로 sort 을 시켜 주어야만 한다.

	int find = 0, location;
	int count = 0, max_count = 0;
	vector<int> sorted; // 정렬된 것들
	vector<int> checked; // 고려된 것들
	string operator_name;

	while (true)
	{
		find = 0;
		count = 0;
		max_count = 0;
		location = 0;

		checked.clear(); // 매번 다시 확인해야 하므로 비워버린다.

		while (find < static_cast<int>(equation.length()))
		{
			if(equation[find] == '{' || equation[find] == '(')
				count ++;
			else if(equation[find] == '}' || equation[find] == ')')
				count --;

			if(equation[find] == '\\' && count > max_count)
			{
				// 찾은게 교환 가능한 연산자 라면
				if(Equation::is_operator(equation, find, operator_name))
				{
					if(Equation::is_changeable(operator_name))
					{
						location = find_outer_open_parenth(find, equation);
						// 정렬한 부분 중에 포함되지 않는다면
						if(!search_vector(sorted, location))
						{
							// 이미 check 한 location 에 포함되지 않는 경우
							// 즉, 만일 {{}\optr1{}\optr2{}} 로 되어 있을 때 각각의
							// optr 들을 지나면서 checked 에 넣을지 말지 결정하는데,
							// 맨 마지막 원소만 확인해 보면 된다. 왜냐면 연속되어 들어 있기 때문..
							// 만일 연속하지 않은 경우, 더 깊숙히 있으므로 역시 고려 안해도 된다.
							if(checked.empty() || location != checked.back())
							{
								checked.push_back(location);
								max_count = count;
							}
						}
					}
				}
			}
			find ++;
		}

		if(max_count == 0) // 식의 처리 완료
			break; 

		// 즉 가장 교환 가능한 연산자가 들어있는 곳을 포함하는 중괄호를 가리킴.
		// 예컨대 {{a}\times{b}} 라면 맨 앞의 { 를 가리키는 셈이다.
		int process_location = checked.back(); 
		int process_location_end = find_match_parenth(process_location, equation);
		string operator_name;

		vector<string> operand_list;
		vector<string> operator_list;

		int find = process_location + 1;

		count = 0;
		while (find < process_location_end)
		{
			// 어차피 이 안에는 교환 가능한 연산자들 밖에 없다. 
			// 따라서 count 가 1 인 것들만 싸그리 모으면 된다.
			if(equation[find] == '{' || equation[find] == '(')
				count ++;
			else if(equation[find] == '}' || equation[find] == ')')
				count --;

			if(count == 1)
			{
				operand_list.push_back(equation.substr(find, find_match_parenth(find, equation) - find + 1));
				find = find_match_parenth(find, equation);
				continue;
			}

			if(count == 0)
			{
				if(equation[find] == '\\')
				{
					if(Equation::is_operator(equation, find, operator_name))
						operator_list.push_back(operator_name);

					find = find + operator_name.length();
				}
			}
			find ++;
		}

		// 이제 operand 들과 operator 들이
		// operand_list 와 operator_list 에 모두 들어가게 되었다.

		string sorted_equation;

		sort(operand_list.begin(), operand_list.end());
		reverse(operand_list.begin(), operand_list.end()); // 큰 것이 앞에 오게
		sort(operator_list.begin(), operator_list.end());
		reverse(operator_list.begin(), operator_list.end());


		// 정렬 되었으면 이제 하나로 합쳐버린다.
		vector<string>::iterator operand_pointer = operand_list.begin();
		vector<string>::iterator operator_pointer = operator_list.begin();

		sorted_equation.append(*operand_pointer);
		operand_pointer ++;

		while (operand_pointer != operand_list.end() && operator_pointer != operator_list.end())
		{
			sorted_equation.push_back('\\');
			sorted_equation.append(*operator_pointer);
			sorted_equation.append(*operand_pointer);

			operator_pointer++;
			operand_pointer++;
		}

		remove_space(sorted_equation);
		equation.replace(process_location + 1, sorted_equation.length(), sorted_equation);
		sorted.push_back(process_location);
	}

	string hash_data;

	remove_space(equation);
	optimize_braket(equation);

	int char_pointer = 0;

	// equation 이 3 으로 안나눠 떨어지면 뒤에 0 을 붙여서 padding 한다. 
	// 즉 3 개 문자를 한 문자로 압축 시켜 버린다. 
	while(equation.length() % 3 != 0)
	{
		equation.push_back(static_cast<char>(0));
	}
	while (char_pointer != equation.length())
	{
		unsigned char hash = equation[char_pointer] + equation[char_pointer + 1] + equation[char_pointer + 2];

		if(hash == '/' || hash == ' ' || hash == '\\' || hash == '\n' || hash == EOF) // 이들은 hash 데이터에서 구분자로 사용된다!
			hash ++;

		hash_data.push_back(hash);
		char_pointer += 3;
	}

	return hash_data;
}
string get_operand_address_table(string equation, double& det)
{
	// 수식 전체를 다시 중괄호로 감싸버린다. 
	equation.insert(0, "{");
	equation.insert(equation.length(), "}");

	map<string, vector<string> > operand_address_table; // <피연산자, 각 피연산자에 작용하는 연산자들 모음>
	vector<string> operand; // 피연산자들을 모음

	map<int, string> operand_locations; //equation 에서 어떤 위치에 어떤 피연산자가 있는지 알려줌

	vector<string>::iterator itr ;
	string operator_name;

	int find = 0;

	// 피연산자들의 목록을 만들어야 한다. 
	while (find < static_cast<int>(equation.length()))
	{
		if(equation[find] == '\\')
		{
			if(Equation::is_operator(equation, find, operator_name))
			{
				find = find + operator_name.length() + 1;
				continue;
			}
			// 연산자가 아닐 경우
			else
			{
				if(search_vec(operand, operator_name) == -1)
				{
					operand.push_back(operator_name);
				}
				// 참고로 operator_name 에는 \ 가 빠져 있으므로 만일 어떤 피연산자를 찾았을 때
				// 처음에 \ 를 찾았다면 이는 \ 가 빠져 있는것

				operand_locations.insert(make_pair(find, operator_name)); // operand 들에 등록되어 있어도 넣어야 한다. 
				find = find + operator_name.length() + 1;
				continue;
			}
		}
		else if(is_alpha(equation[find]))
		{
			char ch = equation[find];
			string c;

			c = ch;

			// 없다면
			if(search_vec(operand, c) == -1)
			{
				operand.push_back(c);
			}
			operand_locations.insert(make_pair(find, c));
		}

		find ++;
	}

	// operand_address_table 에 피연산자들을 등록한다
	vector<string> null_vector;
	null_vector.clear();


	itr = operand.begin();
	while (itr != operand.end())
	{
		operand_address_table.insert(make_pair(*itr, null_vector));
		itr ++;
	}

	map<int, string>::iterator operand_pointer = operand_locations.begin();
	// 이제 operand_address_table 에 피연산자들을 등록한다.
	while (operand_pointer != operand_locations.end())
	{
		int max_count = 1, count = 0;
		find = operand_pointer->first; // 현재 operand 의 위치를 가리키고 있다. 

		while (true)
		{
			while (find > 0)
			{
				if(equation[find] == '{' || equation[find] == '(')
					count ++;
				else if(equation[find] == '}' || equation[find] == ')')
					count --;

				if(count >= max_count)
				{
					vector<string> operand_list;
					// 이 수식을 둘러싸고 있는 중괄호 이다.
					// 즉 { (연산) } 에 해당하는 중괄호

					operand_list = what_operator_braket(equation, find);
					sort(operand_list.begin(), operand_list.end());
					operand_address_table[operand_pointer->second].push_back(vector_to_string(operand_list));

					find --;
					break;
				}

				find --;
			}

			if(find == 0)
				break;

			max_count ++;
		}

		sort(operand_address_table[operand_pointer->second].begin(), operand_address_table[operand_pointer->second].end());
		operand_pointer ++;
	}

	// 이제 operand_address_table 에서 피연산자에 해당하는 부분을 "0" 으로 변경해야 한다.
	// 이렇게 해야지 순위를 쉽게 매길 수 있게 된다 
	map<string, vector<string> >::iterator operand_table_pointer = operand_address_table.begin();

	while (operand_table_pointer != operand_address_table.end())
	{
		vector<string>::iterator itr;
		itr = operand_table_pointer->second.begin(); // 특정 피연산자의 주소 테이블을 가리킨다.

		while (itr != operand_table_pointer->second.end())
		{
			int pointer = 0;
			while (pointer < static_cast<int>(itr->length()))
			{
				if((*itr)[pointer] == '\\')
				{
					// exponent_1 과 같은 경우라도 is_operator 에서는
					// exponent 로 비교하고, 또한 operator_name 에는 
					// exponent_1 을 리턴한다. 
					if(Equation::is_operator(*itr, pointer, operator_name))
					{
						pointer = pointer + operator_name.length() + 1;
						continue;
					}
					else
					{
						itr->replace(pointer, operator_name.length() + 1, "0");
					}
				}
				else if(is_alpha((*itr)[pointer]))
				{
					itr->replace(pointer, 1, "0");
				}
				pointer++;
			}
			itr ++;
		}
		remove_space(operand_table_pointer->second);
		sort(operand_table_pointer->second.begin(), operand_table_pointer->second.end());

		operand_table_pointer++;
	}

	map<string, int> operand_rank; // 특정 피연산자와 순위를 담은 map 으로 순위가 높을 수 록 같이 크다. 
	operand_table_rank(operand_address_table, operand_rank);

	// equation 에서 피연산자들을 찾아서 이를 rank 값으로 치환해야 한다. 
	// operand_locations 를 이용할 수 있다고 생각되겠지만 치환시 위치 관계가 
	// 모두 바뀌므로 다시 하나씩 찾아야만 한다.

	find = 0;
	while (find < static_cast<int>(equation.length()))
	{
		if(equation[find] == '\\')
		{
			if(Equation::is_operator(equation, find, operator_name))
			{
				find = find + operator_name.length() + 1;
				continue;
			}
			else
			{
				if(Equation::is_keyword_operand(operator_name))
				{
					string str = "_" + convert_to_string(operand_rank[operator_name]) + operator_name;
					equation.replace(find, 1 + operator_name.length(), str);
					find = find + str.length();
				}
				else
				{
					// 피연산자일 경우
					string str = "_" + convert_to_string(operand_rank[operator_name]);
					equation.replace(find, 1 + operator_name.length(), str);
					find = find + str.length();
				}
				continue;
			}
		}
		else if(is_alpha(equation[find]))
		{
			string operand_char = convert_to_string(equation[find]);
			string str = "_" + convert_to_string(operand_rank[operand_char]);
			equation.replace(find, 1, str);

			find = find + str.length();
			continue;
		}

		find ++;
	}
	create_relation_matrix(equation, det);
	return equation;
}
void operand_table_rank(map<string, vector<string>> &operand_address_table, map<string, int>& operand_rank)
{
	map<string, vector<string> >::iterator operand_pointer = operand_address_table.begin();

	while (operand_pointer != operand_address_table.end())
	{
		operand_rank.insert(make_pair(operand_pointer->first, 0));
		operand_pointer ++;
	}

	// 모든 원소들과 한 번씩 비교하여 rank 를 결정할 것이다. 
	// 즉 가장 긴 주소를 가진 operand 가 rank 값 자체가 높게 나온다. 
	operand_pointer = operand_address_table.begin();
	while (operand_pointer != operand_address_table.end())
	{
		map<string, vector<string> >::iterator compare_pointer = operand_address_table.begin();
		while (compare_pointer != operand_address_table.end())
		{
			if(operand_pointer->second.empty()) // 주소값이 없을 수 도 있다 !
				break;

			if(compare_pointer == operand_pointer)
			{
				compare_pointer++;
				continue;
			}

			if(operand_pointer->second.size() > compare_pointer->second.size())
			{
				operand_rank[operand_pointer->first]++;
			}
			else if(operand_pointer->second.size() == compare_pointer->second.size())
			{
				if(compare_vector(operand_pointer->second, compare_pointer->second))
					operand_rank[operand_pointer->first] ++;
			}

			compare_pointer ++;
		}
		operand_pointer ++;
	}

}
vector<string> what_operator_braket(string &equation, int location)
{
	// 만일 교환 가능한 이항 연산자들이라면 그 모든 이항 연산자들을 리턴해야 한다.
	// 예를 들어서 {a} \times {b} \times {c} 라면 \times \times 를 리턴해야 한다.
	vector<string> operator_list; 

	string operator_name;

	// 현재 location 은 중괄호를 참조하고 있다
	if(location == 0)
	{
		return operator_list;
	}

	int find = location;
	int count = 0;
	bool is_unary = false;

	find --; // 중괄호 바로 이전을 가리킨다.
	while (find >= 0)
	{
		if(equation[find] == '{' || equation[find] == '(')
			count ++;
		else if(equation[find] == '}' || equation[find] == ')')
			count --;

		if(equation[find] == ' ')
		{
			find --;
			continue;
		}

		if(count == 1)
			break;

		if(count == 0 && equation[find] == '\\')
		{
			if(Equation::is_operator(equation, find, operator_name))
			{
				// 단항 연산자라면
				if(!Equation::is_two_parameter_operator(operator_name) )
				{
					is_unary  = true;
					operator_list.push_back("\\" + operator_name);
					break;
				}
				// 교환 불가능한 이항 연산자라면
				else if(Equation::is_unchangeable(operator_name))
				{
					is_unary = true; // 단항 연산자는 아니지만 피연산자가 한 개 이므로 뒷부분 안찾아봐도 됨.

					// (연산자) (현재 피연산자 위치) 가 되므로
					// (현재 피연산자) 한테는 연산자_2 가 된다. 
					operator_list.push_back("\\" + operator_name + "_2 ");

					count = 0;
					bool start_insert = false;
					string operand_non_change; // 교환 불가능한 이항 연산자의 경우 연산자에 정보에 상대방 피연산자 정보도 넣어야 한다. 

					while (find >= 0)
					{
						if(equation[find] == '}' || equation[find] == ')')
						{
							int loc = find_match_parenth(find, equation);
							// 이 때 중괄호를 포함해서 집어 넣는다.
							operator_list[operator_list.size() - 1].append(equation.substr(loc, find - loc + 1));
							break;
						}
						find --;
					}
					break;

				}
				// 교환 가능한 이항 연산자
				else 
				{
					if(Equation::is_operator(equation, find, operator_name))
					{
						operator_list.push_back("\\" + operator_name);
					}
				}
			}
		}
		find --;
	}

	// 단항 연산자/교환 불가능한 이항 연산자가 아닐 경우 
	// 연산자의 오른쪽 부분에도 연산자들이 작용할 수 있게 된다. 
	if(!is_unary)
	{

		find = find_match_parenth(location, equation);
		find ++;

		count = 0;
		while (find < static_cast<int>(equation.length()))
		{
			if(equation[find] == '{' || equation[find] == '(')
				count ++;
			else if(equation[find] == '}' || equation[find] == ')')
				count --;

			if(equation[find] == ' ')
			{
				find ++;
				continue;
			}

			if(count == -1)
				break;

			if(count == 0 && equation[find] == '\\')
			{
				if(Equation::is_operator(equation, find, operator_name))
				{
					if(Equation::is_unchangeable(operator_name))
					{
						// (현재 피연산자 위치) (연산자) 가 되므로
						// (현재 피연산자) 한테는 연산자_1 가 된다. 
						operator_list.push_back("\\" + operator_name + "_1 ");

						count = 0;
						bool start_insert = false;
						string operand_non_change; // 교환 불가능한 이항 연산자의 경우 연산자에 정보에 상대방 피연산자 정보도 넣어야 한다. 

						while (find < static_cast<int>(equation.length()))
						{
							if(equation[find] == '{' || equation[find] == '(')
							{
								int loc = find_match_parenth(find, equation);
								// 이 때 중괄호를 포함해서 집어 넣는다.
								operator_list[operator_list.size() - 1].append(equation.substr(find, loc - find + 1));
								break;
							}
							find ++;
						}
						break;

					}
					// 교환 가능한 이항 연산자
					else 
					{
						if(Equation::is_operator(equation, find, operator_name))
						{
							operator_list.push_back("\\" + operator_name);
						}
					}
				}
			}

			find ++;
		}
	}

	return operator_list;
}

void Hash::extract_searching_query(string &entire_hash, 
	vector<string> &hash_operand, vector<string> &hash_operator, vector<string> &hash_det)
{
	int find = hash_data.length();
	hash_data.insert(0, " ");

	find --;
	while (find >= 0)
	{
		if(hash_data[find] == '/')
		{
			entire_hash = hash_data.substr(find + 1, hash_data.length() - find - 1);
			break;
		}
		find --;
	}

	bool now_operator = false; // 현재 선택할 것이 연산자 인지 아닌지
	bool now_determinant = true;
	int hash_data_end;

	hash_data_end = find;
	find --;

	while (find >= 0)
	{
		if(hash_data[find] == '/')
			break;
		else if(hash_data[find] == ' ')
		{
			if(now_determinant)
			{
				hash_det.push_back(hash_data.substr(find + 1, hash_data_end - find - 1));
				hash_data_end = find;
				now_determinant = false;
			}
			else if(!now_operator)
			{
				// 현재 선택된 범위는 피연산자 부분임
				hash_operand.push_back(hash_data.substr(find + 1, hash_data_end - find - 1));
				hash_data_end = find;
				now_operator = true;
			}
			else
			{
				hash_operator.push_back(hash_data.substr(find + 1, hash_data_end - find - 1));
				hash_data_end = find;
				now_operator = false;
				now_determinant = true;
			}
		}

		find --;
	}
}